package com.csw.android.ffmpegtest.audio

import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import androidx.annotation.RequiresPermission
import androidx.core.app.ActivityCompat
import com.csw.android.dev_utils.ex.CloseableEx.closeIgnoreException
import com.csw.android.dev_utils.handler.MainHandler
import com.csw.android.dev_utils.utils.LogUtils
import java.io.RandomAccessFile

@SuppressLint("MissingPermission")
class PCMAudioRecordHelper(val filePath: String, val onAudioRecordListener: OnAudioRecordListener) {
    // 音频源：音频输入-麦克风
    private val audioSource = MediaRecorder.AudioSource.MIC

    // 采样率
    // 44100是目前的标准，但是某些设备仍然支持22050，16000，11025
    // 采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级
    private val sampleRateInHz = 16000

    // 音频通道 单声道
    private val channelConfig = AudioFormat.CHANNEL_IN_MONO

    // 音频格式：PCM编码
    private val audioFormat = AudioFormat.ENCODING_PCM_16BIT

    //audioRecord能接受的最小的buffer大小
    private val bufferSize =
        AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)

    //录音控制对象
    private val audioRecord: AudioRecord

    private val mainHandler = MainHandler()

    init {
        audioRecord = AudioRecord(
            audioSource,
            sampleRateInHz,
            channelConfig,
            audioFormat,
            bufferSize
        )
    }

    private var startTime: Long = 0
    private var running: Boolean = false
    fun beginRecord() {
        if (running) {
            return
        }
        startTime = System.currentTimeMillis()
        running = true
        audioRecord.startRecording()
        mainHandler.post { onAudioRecordListener.onRecordStarted(this@PCMAudioRecordHelper) }
        Thread {
            var currTime: Long
            var lastTime = startTime
            var os: RandomAccessFile? = null
            val buffer = ByteArray(bufferSize)
            var read: Int
            try {
                os = RandomAccessFile(filePath, "rw")
                //写入44个字节作为wav文件头占位
                val headInfo = ByteArray(44)
                os.write(headInfo)
                var dataLength = 0
                while (running) {
                    read = audioRecord.read(buffer, 0, bufferSize)
                    if (read > 0) {
                        dataLength += read
                        os.write(buffer, 0, read)
                    }
                    //最多每隔一秒通知一次录制时间
                    currTime = System.currentTimeMillis()
                    if (currTime - lastTime >= 1000) {
                        lastTime = currTime
                        mainHandler.post {
                            onAudioRecordListener.onRecording(
                                this@PCMAudioRecordHelper,
                                startTime,
                                currTime - startTime
                            )
                        }
                    }
                }
                LogUtils.d(this@PCMAudioRecordHelper, "dataLength ${dataLength}")
                os.seek(0)
                //声道数量
                val channels = if (channelConfig == AudioFormat.CHANNEL_IN_MONO) 1 else 2
                setHeadInfo(
                    headInfo,
                    dataLength + 36,
                    dataLength.toInt(),
                    sampleRateInHz,
                    channels,
                    16 * sampleRateInHz * channels / 8
                )
                os.write(headInfo)
                os.seek(os.length())
                LogUtils.d(this@PCMAudioRecordHelper, "fileLength ${os.length()}")
                mainHandler.post { onAudioRecordListener.onRecordCompleted(this@PCMAudioRecordHelper) }
            } catch (e: Exception) {
                e.printStackTrace()
                running = false
                mainHandler.post { onAudioRecordListener.onRecordFailed(this@PCMAudioRecordHelper, e) }
            } finally {
                os.closeIgnoreException()
                audioRecord.stop()
                audioRecord.release()
            }
        }.start()
    }

    private fun setHeadInfo(
        headInfo: ByteArray,
        totalLength: Int,
        dataLength: Int,
        sampleRateInHz: Int,
        channels: Int,
        byteRate: Int
    ) {
        headInfo[0] = 'R'.toByte()
        headInfo[1] = 'I'.toByte()
        headInfo[2] = 'F'.toByte()
        headInfo[3] = 'F'.toByte()
        //totalLength
        headInfo[4] = (totalLength and 0xFF).toByte()
        headInfo[5] = (totalLength shr 8 and 0xFF).toByte()
        headInfo[6] = (totalLength shr 16 and 0xFF).toByte()
        headInfo[7] = (totalLength shr 24 and 0xFF).toByte()
        //WAVE
        headInfo[8] = 'W'.toByte()
        headInfo[9] = 'A'.toByte()
        headInfo[10] = 'V'.toByte()
        headInfo[11] = 'E'.toByte()
        //'fmt' chunk
        headInfo[12] = 'f'.toByte()
        headInfo[13] = 'm'.toByte()
        headInfo[14] = 't'.toByte()
        headInfo[15] = ' '.toByte()
        // 4 bytes: size of 'fmt ' chunk
        headInfo[16] = 16
        headInfo[17] = 0
        headInfo[18] = 0
        headInfo[19] = 0
        // format = 1
        //PCM编码
        headInfo[20] = 1
        headInfo[21] = 0
        //单声道 MONO
        headInfo[22] = channels.toByte()
        headInfo[23] = 0
        //sampleRateInHz
        headInfo[24] = (sampleRateInHz and 0xFF).toByte()
        headInfo[25] = (sampleRateInHz shr 8 and 0xFF).toByte()
        headInfo[26] = (sampleRateInHz shr 16 and 0xFF).toByte()
        headInfo[27] = (sampleRateInHz shr 24 and 0xFF).toByte()
        //byteRate
        headInfo[28] = (byteRate and 0xFF).toByte()
        headInfo[29] = (byteRate shr 8 and 0xFF).toByte()
        headInfo[30] = (byteRate shr 16 and 0xFF).toByte()
        headInfo[31] = (byteRate shr 24 and 0xFF).toByte()
        //block align
        headInfo[32] = (2 * 16 / 8).toByte()
        headInfo[33] = 0
        //bits per sample
        headInfo[34] = 16
        headInfo[35] = 0
        //data
        headInfo[36] = 'd'.toByte()
        headInfo[37] = 'a'.toByte()
        headInfo[38] = 't'.toByte()
        headInfo[39] = 'a'.toByte()
        headInfo[40] = (dataLength and 0xFF).toByte()
        headInfo[41] = (dataLength shr 8 and 0xFF).toByte()
        headInfo[42] = (dataLength shr 16 and 0xFF).toByte()
        headInfo[43] = (dataLength shr 24 and 0xFF).toByte()
    }

    fun endRecord() {
        running = false
    }

    //----------------------------------------------------------------------------------------------
    interface OnAudioRecordListener {

        fun onRecordStarted(helper: PCMAudioRecordHelper)

        fun onRecording(helper: PCMAudioRecordHelper, startTime: Long, duration: Long)

        fun onRecordCompleted(helper: PCMAudioRecordHelper)

        fun onRecordFailed(helper: PCMAudioRecordHelper, exception: Exception)

    }
}